#include "stdafx.h"
#include <boost/test/auto_unit_test.hpp>
#include <sstream>
#include "detail/bmock_in_out_ptr_arg_val.hpp"
#include "bmock_in_out_raw_mem.hpp"
#include "detail/bmock_test_control_tools.hpp"

namespace bmock {
	static const control_tools_ptr         tl(new test_control_tools());
	static const char                      name[] = "arg";
	static const int                       val1   = 127;
	static const int                       val2   = 526;
	static const std::string                    s_val1 = boost::lexical_cast<std::string>(val1);
	static const std::string                    s_val2 = boost::lexical_cast<std::string>(val2);

	BOOST_AUTO_TEST_CASE(test_in_out_ptr_arg_val_get_value) {
		const in_out_raw_mem_descr<int> rm = in_out_raw_mem(val1,val2);
		const arg_val_ptr p_val(make_in_out_arg_val(name,(int *)rm));
		const arg_val_str expected(s_val1,s_val2); 
		arg_checker       al(tl);
		arg_val_str       result;

		BOOST_CHECK_NO_THROW(result = p_val->get_value(al));
		BOOST_CHECK_EQUAL(expected,result);
	}

	BOOST_AUTO_TEST_CASE(test_in_out_ptr_arg_val_print) {
		int               val3 = val1;
		const arg_val_ptr p_val(make_in_out_arg_val(name,&val3));
		const std::string      expected = std::string("IN_OUT(")+boost::lexical_cast<std::string>(val3)+","+out_arg_val::UNKNOWN+")";
		std::ostringstream        os;

		BOOST_CHECK_NO_THROW(p_val->print(os));
		BOOST_CHECK_EQUAL(expected,os.str());
	}

	BOOST_AUTO_TEST_CASE(test_in_out_ptr_arg_val_validate) {
		const arg_val_ptr p_val(make_in_out_arg_val(name,(int *)&val1));
		arg_checker       al(tl);
		const arg_val_str expected(s_val1,s_val2);
		bool              status = true;

		al.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_NO_THROW(status = p_val->validate(al,expected));
		BOOST_CHECK(!status);
	}

	BOOST_AUTO_TEST_CASE(test_in_out_ptr_arg_val_update) {
		int               val3 = 0;
		const arg_val_ptr p_val(make_in_out_arg_val(name,&val3));
		arg_checker       al(tl);
		const arg_val_str expected(s_val1,s_val2); 

		al.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_NO_THROW(p_val->update(al,expected));
		BOOST_CHECK_EQUAL(val2,val3);
	}

	BOOST_AUTO_TEST_CASE(test_in_out_in_ptr_arg_val_get_value) {
		const in_out_raw_mem_descr<int> rm1= in_raw_mem(val1);
		const arg_val_ptr               p_val(make_in_out_arg_val(name,(int *)rm1));
		const arg_val_str               expected(s_val1,IGNORE_STR); 
		arg_checker                     al(tl);
		arg_val_str                     result;

		BOOST_CHECK_NO_THROW(result = p_val->get_value(al));
		BOOST_CHECK_EQUAL(expected,result);
	}

	BOOST_AUTO_TEST_CASE(test_in_out_out_ptr_arg_val_get_value) {
		const in_out_raw_mem_descr<int> rm2= out_raw_mem(val2);
		const arg_val_ptr               p_val(make_in_out_arg_val(name,(int *)rm2));
		const arg_val_str               expected(IGNORE_STR,s_val2); 
		arg_checker                     al(tl);
		arg_val_str                     result;

		BOOST_CHECK_NO_THROW(result = p_val->get_value(al));
		BOOST_CHECK_EQUAL(expected,result);
	}

	BOOST_AUTO_TEST_CASE(test_double_in_out_ptr_get_value) {
		typedef const char *VAL_TYPE;
		VAL_TYPE                             ptr1 = "ABCDEFG";
		raw_mem                              rm_ptr(&ptr1,1);
		const in_out_raw_mem_descr<VAL_TYPE> rm2 = out_raw_mem(&ptr1,1);
		const arg_val_ptr                    p_val(make_in_out_arg_val(name,(VAL_TYPE *)rm2));
		arg_checker                          ac(tl);
		const arg_val_str                    expected(IGNORE_STR,rm_ptr.get_value());

		ac.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_EQUAL(expected,p_val->get_value(ac));
	}

	BOOST_AUTO_TEST_CASE(test_double_in_out_ptr_update) {
		const char       *ptr1 = "ABCDEFG";
		const char       *ptr2 = 0;
		raw_mem           rm_ptr(&ptr1,1);
		const arg_val_ptr p_val(make_in_out_arg_val(name,&ptr2));
		arg_checker       ac(tl);
		const arg_val_str expected(IGNORE_STR,rm_ptr.get_value());
		bool              result = true;

		ac.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_NO_THROW(result = p_val->update(ac,expected));
		BOOST_CHECK(!result);
		BOOST_CHECK_EQUAL(ptr1,ptr2);
	}

	typedef void *MEMORY_TAG;
	BOOST_AUTO_TEST_CASE(test_double_typed_in_out_ptr_get_value) {
		const MEMORY_TAG  tag1 = (MEMORY_TAG)&val1;
		const MEMORY_TAG *ptr1 = &tag1;
		const in_out_raw_mem_descr<MEMORY_TAG> rm2 = out_raw_mem(tag1);
		raw_mem           rm_ptr(ptr1,1);
		const arg_val_ptr p_val(make_in_out_arg_val(name,(MEMORY_TAG *)rm2));
		arg_checker       ac(tl);
		const arg_val_str expected(IGNORE_STR,rm_ptr.get_value());

		ac.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_EQUAL(expected,p_val->get_value(ac));
	}

	BOOST_AUTO_TEST_CASE(test_double_typed_in_out_ptr_update) {
		const MEMORY_TAG  tag1 = (MEMORY_TAG)&val1;
		const MEMORY_TAG *ptr1 = &tag1;
		MEMORY_TAG  tag2 = NULL;
		MEMORY_TAG *ptr2 = &tag2;
		raw_mem           rm_ptr(ptr1,1);
		const arg_val_ptr p_val(make_in_out_arg_val(name,ptr2));
		arg_checker       ac(tl);
		const arg_val_str expected(IGNORE_STR,rm_ptr.get_value());
		bool              result = true;

		ac.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_NO_THROW(result = p_val->update(ac,expected));
		BOOST_CHECK(!result);
		BOOST_CHECK_EQUAL(tag1,tag2);
	}
}
